package com.hth.action

import com.hth.handle.CreateTableDDL
import com.hth.handle.PojoFiledHnadle
import com.hth.model.TableNameAttr
import com.intellij.execution.filters.TextConsoleBuilderFactory
import com.intellij.execution.ui.ConsoleViewContentType
import com.intellij.openapi.actionSystem.ActionUpdateThread
import com.intellij.openapi.actionSystem.AnAction
import com.intellij.openapi.actionSystem.AnActionEvent
import com.intellij.openapi.actionSystem.CommonDataKeys
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project
import com.intellij.openapi.wm.RegisterToolWindowTask
import com.intellij.openapi.wm.ToolWindowAnchor
import com.intellij.openapi.wm.ToolWindowId
import com.intellij.openapi.wm.ToolWindowManager
import com.intellij.psi.*
import com.intellij.psi.util.PsiTreeUtil
import org.jetbrains.kotlin.utils.addToStdlib.ifTrue


class ModelToSqlAction : AnAction() {


    override fun actionPerformed(event: AnActionEvent) {
        val project = event.project
        val psiFile = event.getData(CommonDataKeys.PSI_FILE)
        val editor = event.getData(CommonDataKeys.EDITOR)
        if (editor == null || project == null || psiFile == null || psiFile.isDirectory) {
            return
        }
        val psiclazz = this.getTargetClass(editor, psiFile)
        if (psiclazz != null) {
            // 限制类型
            if (psiclazz.isInterface || psiclazz.isEnum) {
                return
            }
            // 获取所有导入的包
            val packageMap = importPackages(psiFile)

            val handle = PojoFiledHnadle(packageMap,project)
            // 获取表字段
            var fieldList = handle.handel(psiclazz)
            fieldList = fieldList.filter { it.sqlType != null }
            // 获取表属性
            val tableAttr = handle.handleTable(psiclazz, psiFile)
            // 生成sql
            val sql = CreateTableDDL().produce(fieldList, tableAttr)
            // 打开工具面板
            this.showToolWindow(sql, project, tableAttr)
        }
    }

    /**
     * 获取所有导入的包
     */
    private fun importPackages(psiFile: PsiFile): MutableMap<String, String> {
        val map = mutableMapOf<String, String>()
        if (psiFile is PsiJavaFile) {
            psiFile?.importList?.importStatements?.forEach { importStatement ->
                importStatement.importReference?.let {
                    it.canonicalText.apply {
                        map[this.split(".").last()+".class"] = this
                    }
                }
            }
        }
        return map
    }


    /**
     * 显示窗口
     */
    fun showToolWindow(sql: String, project: Project, tableAttr: TableNameAttr) {

        // 获取工具窗口管理器
        val toolWindowManager = ToolWindowManager.getInstance(project)
        // 获取或注册工具窗口
        var toolWindow = toolWindowManager.getToolWindow(ToolWindowId.RUN)
        if (toolWindow == null) {
            // 注册新的工具窗口
            toolWindow = toolWindowManager.registerToolWindow(
                RegisterToolWindowTask(
                    id = ToolWindowId.RUN,
                    anchor = ToolWindowAnchor.BOTTOM,
                    canCloseContent = true,
                    canWorkInDumbMode = true
                )
            )
        }
        // 获取工具窗口的内容管理器
        val contentManager = toolWindow.contentManager
        // 构建当前内容的显示名称
        var displayName = "表[${tableAttr.name}]"
        // 清除和当前tab相同的窗口
        for (content in contentManager?.contents!!) {
            if (content.displayName == displayName) {
                contentManager.removeContent(content, true)
            }
        }
        // 创建控制台视图
        val consoleView = TextConsoleBuilderFactory.getInstance().createBuilder(project).console
        // 创建新的内容
        var content = contentManager.factory?.createContent(consoleView.component, displayName, true)
        content?.let { contentManager.addContent(it) }
        // 清空控制台并打印sql语句
        consoleView.clear()
        consoleView.print(sql, ConsoleViewContentType.NORMAL_OUTPUT)

        // 显示工具窗口
        toolWindow.show()
        if (toolWindow.isVisible) {
            // 显示聚焦当前窗口
            content?.let {
                contentManager.setSelectedContent(it, true)
            }
        }
    }


    /**
     * 只有是java文件才能显示处理
     * @param event
     */
    override fun update(event: AnActionEvent) {
        val virtualFile = event.getData(CommonDataKeys.VIRTUAL_FILE)
        val psiFile = event.getData(CommonDataKeys.PSI_FILE)
        val editor = event.getData(CommonDataKeys.EDITOR)

        // 为空 直接隐藏动作
        if (psiFile == null || editor == null) {
            event.presentation.isVisible = false
            return
        }
        // 获取目标类
        val psiclazz = this.getTargetClass(editor, psiFile)
        // 检查文件类型是否为 JAVA
        val isJavaFile = virtualFile?.fileType?.name == "JAVA"
        // 检查目标类是否满足条件 不能是接口 枚举
        val isClassValid = psiclazz != null && !psiclazz.isInterface && !psiclazz.isEnum
        // 根据条件设置动作的可见性
        event.presentation.isVisible = isJavaFile && isClassValid
    }


    /**
     * 获取目标对象
     * @param editor
     * @param file
     * @return PsiClass
     */
    fun getTargetClass(editor: Editor, file: PsiFile): PsiClass? {
        // 获取编辑器中当前光标的位置偏移量
        val offset = editor.caretModel.offset
        // 在 PsiFile 中查找该偏移量位置对应的 PsiElement
        return file.findElementAt(offset)?.let { element ->
            // 查找该元素的最近的 PsiClass 类型的父元素
            val target = PsiTreeUtil.getParentOfType(element, PsiClass::class.java)
            // 过滤合成元素，如果是合成元素则返回 null，否则返回该 PsiClass 对象
            if (target is SyntheticElement) null else target
        }
    }

    /**
     * ActionUpdateThread.OLD_EDT 已被弃用
     * 重写 getActionUpdateThread 指定线程
     */
    override fun getActionUpdateThread(): ActionUpdateThread {
        // EDT（事件调度线程）和 BGT（后台线程）中做出选择。
        return ActionUpdateThread.BGT
    }
}
